#include <stdio.h>
// 指针和数组笔试题

// //一维数组
// int main()
// {
//     int a[] = {1,2,3,4};//此为64位环境
//     printf("%d\n",sizeof(a));//sizeof 数组名代表整个数组 16
//     printf("%d\n",sizeof(a+0));//首元素地址  8
//     printf("%d\n",sizeof(*a));//首元素  4
//     printf("%d\n",sizeof(a+1));//次元素的地址  8
//     printf("%d\n",sizeof(a[1]));//首元素  4
//     printf("%d\n",sizeof(&a));//数组地址  8
//     printf("%d\n",sizeof(*&a));//整个数组的大小  16
//     printf("%d\n",sizeof(&a+1));//跳过a数组之后的数组的地址  8
//     printf("%d\n",sizeof(&a[0]));//首元素地址  8
//     printf("%d\n",sizeof(&a[0]+1));//次元素地址  8
//     return 0;
// }

// // 字符数组
// #include <string.h>
// int main()
// {
//     // char arr[] = {'a', 'b', 'c', 'd', 'e', 'f'};
//     // printf("%d\n", sizeof(arr));//6
//     // printf("%d\n", sizeof(arr + 0));//4或8 数组首元素的地址 第一遍做错
//     // printf("%d\n", sizeof(*arr));//1
//     // printf("%d\n", sizeof(arr[1]));//1
//     // printf("%d\n", sizeof(&arr));//8
//     // printf("%d\n", sizeof(&arr + 1));//8
//     // printf("%d\n", sizeof(&arr[0] + 1));//8
//     // printf("%d\n", strlen(arr));//随机值 第一次错
//     // printf("%d\n", strlen(arr + 0));//随机值
//     // printf("%d\n", strlen(*arr));//strlen('a')->strlen(97) 野指针 报错
//     // printf("%d\n", strlen(arr[1]));//与上一行同理 报错
//     // printf("%d\n", strlen(&arr));//随机值
//     // printf("%d\n", strlen(&arr+1));//随机值-6
//     // printf("%d\n", strlen(&arr[0]+1));//随机值-1

//     char arr[] = "abcdef";
//     printf("%d\n", sizeof(arr));//6 x  为7  arr[6] = '\0'
//     printf("%d\n", sizeof(arr + 0));//1 x  为arr的地址 4或8
//     printf("%d\n", sizeof(*arr));//1
//     printf("%d\n", sizeof(arr[1]));//1
//     printf("%d\n", sizeof(&arr));//8
//     printf("%d\n", sizeof(&arr + 1));//8
//     printf("%d\n", sizeof(&arr[0] + 1));//8
//     //sizeof与strlen不同
//     printf("%d\n", strlen(arr));//6
//     printf("%d\n", strlen(arr + 0));//6
//     printf("%d\n", strlen(*arr));//错误
//     printf("%d\n", strlen(arr[1]));//错误
//     printf("%d\n", strlen(&arr));//6
//     printf("%d\n", strlen(&arr + 1));//随机值
//     printf("%d\n", strlen(&arr[0] + 1));//5

//     char *p = "abcdef";//将首字符'a'的地址放到p中
//     printf("%d\n", sizeof(p));//8
//     printf("%d\n", sizeof(p + 1));//8
//     printf("%d\n", sizeof(*p));//1
//     printf("%d\n", sizeof(p[0]));//1
//     printf("%d\n", sizeof(&p));//8
//     printf("%d\n", sizeof(&p + 1));//8
//     printf("%d\n", sizeof(&p[0] + 1));//8

//     printf("%d\n", strlen(p));//6
//     printf("%d\n", strlen(p + 1));//5
//     printf("%d\n", strlen(*p));//错误
//     printf("%d\n", strlen(p[0]));//6 x  应为错误
//     printf("%d\n", strlen(&p));//6 x  随机值（取指针p的地址 即从p的起始位置数字符数）
//     printf("%d\n", strlen(&p + 1));//错误 x 随机值 且和上行值无关系
//     printf("%d\n", strlen(&p[0] + 1));//5
//     return 0;
// }

// // 二维数组
// int main()
// {
//     int a[3][4] = {0};
//     printf("%d\n", sizeof(a));//48
//     printf("%d\n", sizeof(a[0][0]));//4
//     printf("%d\n", sizeof(a[0]));//4 x  第一行 16
//     printf("%d\n", sizeof(a[0] + 1));//4 x 第一行第二个元素的地址 为8
//     printf("%d\n", sizeof(*(a[0] + 1)));//8 x  解引用 为int型数据 为4
//     printf("%d\n", sizeof(a + 1));//8
//     printf("%d\n", sizeof(*(a + 1)));//4 x a作为二维数组名不单独使用时
//     //代表首元素地址 即第一行的地址 +1则为第二行的地址 解引用代表第二行
//     //所以应为16
//     printf("%d\n", sizeof(&a[0] + 1));//8
//     printf("%d\n", sizeof(*(&a[0] + 1)));//4 x
//     //取地址a[0]，此时a[0]作为数组名 代表第一行的地址 +1则为第二行
//     //解引用也为第二行 正确答案为16
//     printf("%d\n", sizeof(*a));//4 x 首行地址解引用 应为16
//     printf("%d\n", sizeof(a[3]));//4 x 第四行的大小 也为16 但是越界了
//     return 0;
// }






// 指针笔试题

// int main()
// {
//     int a[5] = {1, 2, 3, 4, 5};
//     int *ptr = (int *)(&a + 1);
//     printf("%d,%d", *(a + 1), *(ptr - 1));//2，5
//     return 0;
// }



// // 由于还没学习结构体，这里告知结构体的大小是20个字节
// struct Test
// {
//     int Num;
//     char *pcName;
//     short sDate;
//     char cha[2];
//     short sBa[4];
// } *p = (struct Test*)0x100000;
// // 假设p 的值为0x100000。 如下表表达式的值分别为多少？
// // 已知，结构体Test类型的变量大小是20个字节（x86环境下）
// int main()
// {
//     printf("%p\n", p + 0x1);//0x100014
//     printf("%p\n", (unsigned long)p + 0x1);//0x100009 x  
//     //此处是强制类型转换成整数再加1 结果为0x100001
//     printf("%p\n", (unsigned int *)p + 0x1);//0x100005 x
//     //此处是转换成int*类型的指针，结果为0x100004
//     return 0;
// }



// int main()
// {
//     int a[4] = { 1, 2, 3, 4 };
//     int *ptr1 = (int *)(&a + 1);
//     int *ptr2 = (int *)((int)a + 1);
//     printf( "%x,%x", ptr1[-1], *ptr2);
//     //结果为4，2  错误  应为4，02000000 第二个涉及到小端存储
//     //01000000 02000000 03000000 04000000
//     //01  00000002 00000003...... 
//     //00000002以小端形式取出结果为02000000
//     return 0;
// }



// int main()
// {
//     int a[3][2] = { (0, 1), (2, 3), (4, 5) };
//     int *p;
//     p = a[0];
//     printf( "%d", p[0]);//a[0]表示首元素的地址 即a[0][0]
//     return 0;
// }



// int main()
// {
//     int a[5][5];
//     int(*p)[4];
//     p = (int(*)[4])a;
//     printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
//     return 0;
//     //fffffffffffffffc,-4
// }


// int main()
// {
//     int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
//     int *ptr1 = (int *)(&aa + 1);
//     int *ptr2 = (int *)(*(aa + 1));
//     printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10,5
//     return 0;
// }



// int main()
// {
//     char *a[] = {"work","at","alibaba"};
//     char**pa = a;
//     pa++;
//     printf("%s\n", *pa);
//     return 0;
// }



int main()
{
    char *c[] = {"ENTER","NEW","POINT","FIRST"};
    char**cp[] = {c+3,c+2,c+1,c};
    char***cpp = cp;
    printf("%s\n", **++cpp);//POINT 注意此时cpp的值/cpp指向位置已经变了！！！！
    printf("%s\n", *--*++cpp+3);//ER
    //上面两行代码中的++和—-都会改变值！！！！！！！！！
    printf("%s\n", *cpp[-2]+3);//ST
    printf("%s\n", cpp[-1][-1]+1);//EW
    //上面两行不会改变cpp的值
    return 0;
}